using System;
using System.Collections.Generic;
using DNT.RavenQA.Core.Extensions;
using DNT.RavenQA.Core.Models;

namespace DNT.RavenQA.Web.Infrastructure.Commands
{
    public static class VoteCommandFactory
    {
        public static VoteCommand BuildUp(String contributeType, Int32 id, User user)
        {
            return Build(contributeType, id, user, true);
        }

        public static VoteCommand BuildDown(String contributeType, Int32 id, User user)
        {
            return Build(contributeType, id, user, false);
        }

        private static VoteCommand Build(String contributeType, Int32 id, User user, Boolean up)
        {
            contributeType.EnsureIsNotNullOrEmpty("contributeType");
            var tuple = new Tuple<String, Boolean>(contributeType.ToLowerInvariant(), up);

            if (!Commands.ContainsKey(tuple))
                throw new NotSupportedException();

            return Commands[tuple](id, user);
        }

        private static readonly IDictionary<Tuple<String, Boolean>, Func<Int32, User, VoteCommand>> Commands = new Dictionary<Tuple<String, Boolean>, Func<Int32, User, VoteCommand>>()
                                                                                                                   {
                                                                                                                       { new Tuple<String, Boolean>("answer", true), NewUp<Answer> },
                                                                                                                       { new Tuple<String, Boolean>("question", true), NewUp<Question> },
                                                                                                                       { new Tuple<String, Boolean>("answer", false), NewDown<Answer> },
                                                                                                                       { new Tuple<String, Boolean>("question", false), NewDown<Question> }
                                                                                                                   };

        private static VoteCommand NewUp<TContribute>(Int32 id, User user) where TContribute : Contribute
        {
            return new VoteUpCommand<TContribute>(new VoteCommand.Input
                                                      {
                                                          ContributeId = id,
                                                          User = user
                                                      });
        }

        private static VoteCommand NewDown<TContribute>(Int32 id, User user) where TContribute : Contribute
        {
            return new VoteDownCommand<TContribute>(new VoteCommand.Input
                                                        {
                                                            ContributeId = id,
                                                            User = user
                                                        });
        }
    }
}